/*
 简单可复用的 6×22 矩阵灯数据计算模块
 使用方法：
   const result = computeMatrix6x22(detailed22Array, {
       rows: 6,
       cols: 22,
       minDbCut: -50,     // 低于此分贝直接熄灭
       maxDb: -20,        // 顶阈值（对应你的滑块）
       gamma: 0.7,        // 亮度压缩，接近听感
       minDisplay: 0.05   // 最低显示亮度
   });
 返回结果：
   {
     rows, cols,
     levels: number[rows][cols]  // 每格 0..6 的整数层级
     values: number[rows][cols]  // 每格 0..1 的亮度值
     colLevels: number[cols]     // 每列 0..rows 的层数
     stats: { avgDb, maxDb, minDb }
   }
 该函数无框架依赖，可在任何 Web/Electron/Node 环境复用。
*/

export interface MatrixComputeOptions {
  rows?: number;
  cols?: number;
  minDbCut?: number;
  maxDb?: number;
  gamma?: number;
  minDisplay?: number;
}

export interface MatrixResult {
  rows: number;
  cols: number;
  levels: number[][];
  values: number[][];
  colLevels: number[];
  stats: {
    max: any;
    avg: any;
    avgDb: number;
    maxDb: number;
    minDb: number;
  };
}

function clamp(v: number, min: number, max: number): number {
  return Math.max(min, Math.min(max, v));
}

export function computeMatrix6x22(
  detailedBars: number[],
  options?: MatrixComputeOptions
): MatrixResult {
  const cfg = Object.assign(
    {
      rows: 6,
      cols: 22,
      minDbCut: -50,
      maxDb: -20,
      gamma: 0.7,
      minDisplay: 0.05,
    },
    options || {}
  );

  const rows = cfg.rows,
    cols = cfg.cols;
  const levels: number[][] = Array.from({ length: rows }, () =>
    Array(cols).fill(0)
  );
  const values: number[][] = Array.from({ length: rows }, () =>
    Array(cols).fill(0)
  );
  const colLevels: number[] = Array(cols).fill(0);

  let sumDb = 0,
    cntDb = 0;
  let maxDb = -Infinity,
    minDb = Infinity;

  for (let col = 0; col < cols; col++) {
    const raw = clamp(detailedBars[col] || 0, 0, 255);
    // 0..255 → -60..0 dB 的近似映射
    const db = (raw / 255) * 60 - 60;
    if (db < cfg.minDbCut) {
      colLevels[col] = 0;
      continue;
    }
    // 归一化到 0..1
    const norm = clamp((db - cfg.minDbCut) / (cfg.maxDb - cfg.minDbCut), 0, 1);
    // gamma 压缩（接近人耳）
    const brightness = Math.pow(norm, cfg.gamma);
    const level = clamp(Math.round(brightness * rows), 0, rows);
    colLevels[col] = level;

    // 统计
    maxDb = Math.max(maxDb, db);
    minDb = Math.min(minDb, db);
    sumDb += db;
    cntDb++;

    // 自底向上点亮
    const disp = Math.max(cfg.minDisplay, brightness);
    for (let r = rows - 1; r >= rows - level; r--) {
      if (r >= 0) {
        levels[r][col] = rows - r; // 1..rows
        values[r][col] = disp; // 0..1
      }
    }
  }

  return {
    rows,
    cols,
    levels,
    values,
    colLevels,
    stats: {
      avgDb: cntDb ? sumDb / cntDb : -60,
      maxDb: isFinite(maxDb) ? maxDb : -60,
      minDb: isFinite(minDb) ? minDb : -60,
      max: 0,
      avg: 0,
    },
  };
}
